/* Vecmath.

   Copyright (C) 2001, 2002, 2003 Stefan Maierhofer.

   Written by Stefan Maierhofer <sm@cg.tuwien.ac.at>

   This file is part of Vecmath.

   Vecmath is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   Vecmath is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with Vecmath; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */

using System;
using NUnit.Framework;

namespace Vecmath
{

    /// <summary>
    /// Shift2D.
    /// </summary>
    public struct Shift2D
    {

        public static Shift2D Identity = new Shift2D(0,0);

        public Shift2D(double x, double y)
        {
            v = new Vec2D(x,y);
        }

        public Shift2D(Vec2D shift)
        {
            v = shift;
        }

        public double x { get { return v._x[0]; } }
        public double y { get { return v._x[1]; } }

        public Trafo2D ToTrafo2D()
        {
            return new Trafo2D(
                1, 0, 0,
                0, 1, 0,
                v._x[0], v._x[1], 1
                );
        }

        public static implicit operator Trafo2D(Shift2D r)
        {
            return r.ToTrafo2D();
        }

        public static Shift2D operator*(Shift2D a, Shift2D b)
        {
            return new Shift2D(a.v + b.v);
        }

        public static Trafo2D operator*(Scale2D a, Shift2D b)
        {
            return new Trafo2D(
                a.x, 0, 0,
                0, a.y, 0,
                b.x, b.y, 1
                );
        }

        public static Trafo2D operator*(Rot2D a, Shift2D b)
        {
            return a.ToTrafo2D() * b.ToTrafo2D();
        }

        public static Trafo2D operator*(Trafo2D a, Shift2D b)
        {
            a._x[6] += b.x;
            a._x[7] += b.y;
            return a;
        }

        public static Vec2D operator*(Vec2D v, Shift2D t)
        {
            return v;
        }

        public static Pnt2D operator*(Pnt2D p, Shift2D t)
        {
            return p + t.v;
        }

        private Vec2D v;

    }



    [TestFixture]
    public class Shift2DTest
    {
       
        [Test]
        public void MulPnt()
        {
            Shift2D t = new Shift2D(4,5);
            Pnt2D p = new Pnt2D(2,3);
            Assert.IsTrue(Vecmath.ApproxEquals(new Pnt2D(6,8), p * t));
        }

        [Test]
        public void MulVec()
        {
            Shift2D t = new Shift2D(4,5);
            Vec2D v = new Vec2D(2,3);
            Assert.IsTrue(Vecmath.ApproxEquals(new Vec2D(2,3), v * t));
        }

        [Test]
        public void MulScale()
        {
            Shift2D t = new Shift2D(4,5);
            Pnt2D p = new Pnt2D(2,3);
            Scale2D s = new Scale2D(2,3);
            Assert.IsTrue(Vecmath.ApproxEquals(new Pnt2D(8,14), p * (s * t)));
        }

        [Test]
        public void MulRot()
        {
            Shift2D t = new Shift2D(4,5);
            Pnt2D p = new Pnt2D(2,3);
            Rot2D r = new Rot2D(Math.PI / 2.0);
            Assert.IsTrue(Vecmath.ApproxEquals(new Pnt2D(1,7), p * (r * t)));
        }

        [Test]
        public void MulTrafo()
        {
            Shift2D t = new Shift2D(4,5);
            Pnt2D p = new Pnt2D(2,3);
            Rot2D r = new Rot2D(Math.PI / 2.0);
            Assert.IsTrue(Vecmath.ApproxEquals(p * (r * t), p * (r.ToTrafo2D() * t)));
        }

    }

}
